/********************************************************************************
 * Copyright (c) 2011-2017 Red Hat Inc. and/or its affiliates and others
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 1.0 which is available at
 * http://www.eclipse.org/legal/epl-v10.html.
 *
 * SPDX-License-Identifier: EPL-1.0
 ********************************************************************************/
package org.eclipse.ceylon.ide.eclipse.code.complete;

import static org.eclipse.ceylon.ide.eclipse.code.hover.DocumentationHover.getDocumentationFor;

import java.util.List;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContextInformation;

import org.eclipse.ceylon.compiler.typechecker.tree.Node;
import org.eclipse.ceylon.compiler.typechecker.tree.Tree;
import org.eclipse.ceylon.compiler.typechecker.tree.Visitor;
import org.eclipse.ceylon.ide.eclipse.code.parse.CeylonParseController;
import org.eclipse.ceylon.model.typechecker.model.Declaration;
import org.eclipse.ceylon.model.typechecker.model.Functional;
import org.eclipse.ceylon.model.typechecker.model.ParameterList;
import org.eclipse.ceylon.model.typechecker.model.Reference;
import org.eclipse.ceylon.model.typechecker.model.Scope;
import org.eclipse.ceylon.model.typechecker.model.Unit;

public class InvocationCompletionProposal extends CompletionProposal {
    
//    private static final List<Type> NO_TYPES = Collections.<Type>emptyList();

//    @Deprecated
//    static void addProgramElementReferenceProposal(
//            int offset, String prefix,
//            CeylonParseController controller,
//            List<ICompletionProposal> result,
//            Declaration dec, Scope scope, boolean isMember) {
//        Unit unit = controller.getLastCompilationUnit().getUnit();
//        result.add(new InvocationCompletionProposal(
//                offset, prefix,
//                dec.getName(unit), escaping_.get_().escapeName(dec, unit),
//                dec, dec.getReference(), scope, controller,
//                true, false, false, false, isMember, null));
//    }
//    
//    @Deprecated
//    static void addReferenceProposal(
//            int offset, String prefix,
//            final CeylonParseController controller,
//            List<ICompletionProposal> result, 
//            DeclarationWithProximity dwp,
//            Scope scope, boolean isMember,
//            Reference pr, OccurrenceLocation ol) {
//        Unit unit = controller.getLastCompilationUnit().getUnit();
//        Declaration dec = dwp.getDeclaration();
//        //proposal with type args
//        if (dec instanceof Generic) {
//            result.add(new InvocationCompletionProposal(
//                    offset, prefix,
//                    getDescriptionFor(dwp, unit, true),
//                    getTextFor(dec, unit), 
//                    dec, pr, scope, controller,
//                    true, false, false,
//                    ol==UPPER_BOUND ||
//                    ol==EXTENDS ||
//                    ol==SATISFIES,
//                    isMember, null));
//            Generic g = (Generic) dec;
//            if (g.getTypeParameters().isEmpty()) {
//                //don't add another proposal below!
//                return;
//            }
//        }
//        //proposal without type args
//        boolean isAbstract = 
//                dec instanceof Interface ||
//                dec instanceof Class && 
//                    ((Class) dec).isAbstract();
//        if ((!isAbstract && 
//                ol!=EXTENDS && ol!=SATISFIES && ol!=UPPER_BOUND ||
//                ol!=CLASS_ALIAS && ol!=TYPE_ALIAS)) {
//            result.add(new InvocationCompletionProposal(
//                    offset, prefix,
//                    getDescriptionFor(dwp, unit, false),
//                    escaping_.get_().escapeName(dec, unit), 
//                    dec, pr, scope, controller,
//                    true, false, false, false,
//                    isMember, null));
//        }
//    }
//    
//    @Deprecated
//    static void addSecondLevelProposal(
//            int offset, String prefix, 
//            CeylonParseController controller, 
//            List<ICompletionProposal> result, 
//            Declaration dec, Scope scope, 
//            boolean isMember, Reference pr,
//            Type requiredType, OccurrenceLocation ol) {
//        Unit unit =
//                controller.getLastCompilationUnit()
//                    .getUnit();
//        Type type = pr.getType();
//        if (type!=null) {
//            if (!(dec instanceof Functional) &&
//                !(dec instanceof TypeDeclaration)) {
//                //add qualified member proposals
//                Collection<DeclarationWithProximity> members =
//                        type.getDeclaration()
//                            .getMatchingMemberDeclarations(
//                                    unit, scope, "", 0)
//                            .values();
//                for (DeclarationWithProximity ndwp: members) {
//                    Declaration m = ndwp.getDeclaration();
//                    if ((m instanceof FunctionOrValue ||
//                            m instanceof Class) &&
//                            !m.isConstructor()) {
//                        if (m.isAbstraction()) {
//                            for (Declaration o:
//                                    m.getOverloads()) {
//                                addSecondLevelProposal(
//                                        offset, prefix,
//                                        controller, result, dec,
//                                        scope, requiredType, ol,
//                                        unit, type, ndwp, o);
//                            }
//                        }
//                        else {
//                            addSecondLevelProposal(
//                                    offset, prefix,
//                                    controller, result, dec,
//                                    scope, requiredType, ol,
//                                    unit, type, ndwp, m);
//                        }
//                    }
//                }
//            }
//            if (dec instanceof Class) {
//                //add constructor proposals
//                List<Declaration> members =
//                        type.getDeclaration()
//                            .getMembers();
//                for (Declaration m: members) {
//                    if (m instanceof FunctionOrValue &&
//                            m.isConstructor() &&
//                            m.isShared() &&
//                            m.getName()!=null) {
//                        addSecondLevelProposal(
//                                offset, prefix,
//                                controller, result, dec,
//                                scope, requiredType, ol,
//                                unit, type, null, m);
//                    }
//                }
//            }
//        }
//    }
//
//    @Deprecated
//    private static void addSecondLevelProposal(
//            int offset, String prefix,
//            CeylonParseController controller, 
//            List<ICompletionProposal> result,
//            Declaration dec, Scope scope,
//            Type requiredType, OccurrenceLocation ol,
//            Unit unit, Type type,
//            DeclarationWithProximity mwp,
//            // sometimes we have no mwp so we also need the m
//            Declaration m) {
//        Reference ptr = type.getTypedReference(m, NO_TYPES);
//        Type mt = ptr.getType();
//        if (mt!=null && 
//                (requiredType==null ||
//                 withinBounds(requiredType, mt, scope) ||
//                 dec instanceof Class &&
//                     dec.equals(requiredType.getDeclaration()))) {
//            String qualifier = dec.getName() + ".";
//            String desc = 
//                    qualifier + 
//                    getPositionalInvocationDescriptionFor(
//                            mwp, m, ol, ptr, unit, false, null);
//            String text = 
//                    qualifier + 
//                    getPositionalInvocationTextFor(
//                            m, ol, ptr, unit, false, null);
//            result.add(new InvocationCompletionProposal(
//                    offset, prefix, desc, text, m, ptr, scope, 
//                    controller, true, true, false,
//                    ol==UPPER_BOUND ||
//                    ol==EXTENDS ||
//                    ol==SATISFIES,
//                    true, dec));
//        }
//    }
//    
//    @Deprecated
//    static void addInvocationProposals(
//            int offset, String prefix, 
//            CeylonParseController controller,
//            List<ICompletionProposal> result, 
//            DeclarationWithProximity dwp,
//            // sometimes we have no dwp, just a dec, so we have to handle that too
//            Declaration dec,
//            Reference pr,
//            Scope scope, OccurrenceLocation ol,
//            String typeArgs, boolean isMember) {
//        if (dec instanceof Functional) {
//            Unit unit =
//                    controller.getLastCompilationUnit()
//                        .getUnit();
//            boolean isAbstract = 
//                    dec instanceof TypeDeclaration && 
//                    ((TypeDeclaration) dec).isAbstract();
//            Functional fd = (Functional) dec;
//            List<ParameterList> pls = fd.getParameterLists();
//            if (!pls.isEmpty()) {
//                ParameterList parameterList = pls.get(0);
//                List<Parameter> ps = 
//                        parameterList.getParameters();
//                String inexactMatches = 
//                        getPreferences()
//                            .getString(INEXACT_MATCHES);
//                boolean exact = 
//                        prefixWithoutTypeArgs(prefix, typeArgs)
//                            .equalsIgnoreCase(dec.getName(unit));
//                boolean positional = 
//                        exact ||
//                        "both".equals(inexactMatches) || 
//                        "positional".equals(inexactMatches);
//                boolean named = 
//                        exact ||
//                        "both".equals(inexactMatches);
//                boolean inheritance =
//                        ol==UPPER_BOUND ||
//                        ol==EXTENDS ||
//                        ol==SATISFIES;
//                if (positional &&
//                        parameterList.isPositionalParametersSupported() &&
//                        (!isAbstract || 
//                                ol==EXTENDS || ol==CLASS_ALIAS)) {
//                    List<Parameter> parameters = 
//                            getParameters(parameterList, 
//                                    false, false);
//                    if (ps.size()!=parameters.size()) {
//                        String desc = 
//                                getPositionalInvocationDescriptionFor(
//                                        dwp, dec, ol, pr, unit, false,
//                                        typeArgs);
//                        String text = 
//                                getPositionalInvocationTextFor(
//                                        dec, ol, pr, unit, false, 
//                                        typeArgs);
//                        result.add(new InvocationCompletionProposal(
//                                offset, prefix, desc, text, dec, pr, scope, 
//                                controller, false, true, false,
//                                inheritance, isMember, null));
//                    }
//                    String desc = 
//                            getPositionalInvocationDescriptionFor(
//                                    dwp, dec, ol, pr, unit, true,
//                                    typeArgs);
//                    String text = 
//                            getPositionalInvocationTextFor(
//                                    dec, ol, pr, unit, true, 
//                                    typeArgs);
//                    result.add(new InvocationCompletionProposal(
//                            offset, prefix, desc, text, dec, pr, scope, 
//                            controller, true, true, false,
//                            inheritance, isMember, null));
//                }
//                if (named && 
//                        parameterList.isNamedParametersSupported() &&
//                        (!isAbstract && 
//                                ol!=EXTENDS && ol!=CLASS_ALIAS &&
//                                !dec.isOverloaded())) {
//                    //if there is at least one parameter, 
//                    //suggest a named argument invocation
//                    List<Parameter> parameters = 
//                            getParameters(parameterList, false, true);
//                    if (ps.size()!=parameters.size()) {
//                        String desc = 
//                                getNamedInvocationDescriptionFor(
//                                        dec, pr, unit, false, 
//                                        typeArgs);
//                        String text = 
//                                getNamedInvocationTextFor(
//                                        dec, pr, unit, false, 
//                                        typeArgs);
//                        result.add(new InvocationCompletionProposal(
//                                offset, prefix, desc, text, dec, pr, scope, 
//                                controller, false, false, true,
//                                inheritance, isMember, null));
//                    }
//                    if (!ps.isEmpty()) {
//                        String desc = 
//                                getNamedInvocationDescriptionFor(
//                                        dec, pr, unit, true, 
//                                        typeArgs);
//                        String text = 
//                                getNamedInvocationTextFor(
//                                        dec, pr, unit, true, 
//                                        typeArgs);
//                        result.add(new InvocationCompletionProposal(
//                                offset, prefix, desc, text, dec, pr, scope, 
//                                controller, true, false, true,
//                                inheritance, isMember, null));
//                    }
//                }
//            }
//        }
//    }

//    private static String prefixWithoutTypeArgs(
//            String prefix, String typeArgs) {
//        if (typeArgs==null) {
//            return prefix;
//        }
//        else {
//            return prefix.substring(0, 
//                    prefix.length()-typeArgs.length());
//        }
//    }
    
//    @Deprecated
//    final class NestedCompletionProposal
//            implements ICompletionProposal, 
//                       ICompletionProposalExtension2,
//                       ICompletionProposalExtension6 {
//        private final String op;
//        private final int loc;
//        private final int index;
//        private final boolean basic;
//        private final Declaration dec;
//        private Declaration qualifier;
//        
//        NestedCompletionProposal(
//                Declaration dec, Declaration qualifier, 
//                int loc, int index, boolean basic, 
//                String op) {
//            this.qualifier = qualifier;
//            this.op = op;
//            this.loc = loc;
//            this.index = index;
//            this.basic = basic;
//            this.dec = dec;
//        }
//
//        public String getAdditionalProposalInfo() {
//            return null;
//        }
//
//        @Override
//        public void apply(IDocument document) {
//            //the following awfulness is necessary because the
//            //insertion point may have changed (and even its
//            //text may have changed, since the proposal was
//            //instantiated).
//            try {
//                IRegion region =
//                        getCurrentArgumentRegion(document,
//                                loc, index,
//                                getFirstPosition());
//                String str = getText(false);
//                int start = region.getOffset();
//                int len = region.getLength();
//                int end = start + len;
//                if (document.getChar(end)=='}') {
//                    str += " ";
//                }
//                document.replace(start, len, str);
//            } 
//            catch (BadLocationException e) {
//                e.printStackTrace();
//            }
//            //adding imports drops us out of linked mode :(
//            //not needed anyway because we never propose
//            //unimported stuff, so no big deal
//            /*try {
//                DocumentChange tc = 
//                        new DocumentChange("imports", document);
//                tc.setEdit(new MultiTextEdit());
//                HashSet<Declaration> decs = 
//                        new HashSet<Declaration>();
//                Tree.CompilationUnit cu = cpc.getRootNode();
//                importDeclaration(decs, dec, cu);
//                if (dec instanceof Functional) {
//                    List<ParameterList> pls = 
//                            ((Functional) dec).getParameterLists();
//                    if (!pls.isEmpty()) {
//                        for (Parameter p: pls.get(0).getParameters()) {
//                            FunctionOrValue pm = p.getModel();
//                            if (pm instanceof Function) {
//                                for (ParameterList ppl: 
//                                        ((Function) pm).getParameterLists()) {
//                                    for (Parameter pp: ppl.getParameters()) {
//                                        importSignatureTypes(pp.getModel(), cu, decs);
//                                    }
//                                }
//                            }
//                        }
//                    }
//                    
//                }
//                applyImports(tc, decs, cu, document);
//                EditorUtil.performChange(tc);
//            }
//            catch (Exception e) {
//                e.printStackTrace();
//            }*/
//        }
//
//        private String getText(boolean description) {
//            StringBuilder sb = new StringBuilder(op);
//            Unit unit = getUnit();
//            sb.append(getProposedName(qualifier, dec, unit));
//            if (dec instanceof Functional && !basic) {
//                appendPositionalArgs(dec, unit, sb, false,
//                        description);
//            }
//            return sb.toString();
//        }
//
//        @Override
//        public Point getSelection(IDocument document) {
//            return null;
//        }
//
//        @Override
//        public String getDisplayString() {
//            return getText(true);
//        }
//        
//        @Override
//        public StyledString getStyledDisplayString() {
//            StyledString result = new StyledString();
//            Highlights.styleFragment(result, 
//                    getDisplayString(), false, null, 
//                    getCompletionFont());
//            return result;
//        }
//
//        @Override
//        public Image getImage() {
//            return getImageForDeclaration(dec);
//        }
//
//        @Override
//        public IContextInformation getContextInformation() {
//            return null;
//        }
//
//        @Override
//        public void apply(ITextViewer viewer, char trigger, 
//                int stateMask, int offset) {
//            apply(viewer.getDocument());
//        }
//
//        @Override
//        public void selected(ITextViewer viewer, boolean smartToggle) {}
//
//        @Override
//        public void unselected(ITextViewer viewer) {}
//
//        @Override
//        public boolean validate(IDocument document,
//                int currentOffset, DocumentEvent event) {
//            if (event==null) {
//                return true;
//            }
//            else {
//                try {
//                    IRegion region =
//                            getCurrentArgumentRegion(document,
//                                    loc, index,
//                                    getFirstPosition());
//                    String content = 
//                            document.get(region.getOffset(),
//                                    currentOffset-region.getOffset());
//                    return isContentValid(content);
//                }
//                catch (BadLocationException e) {
//                    // ignore concurrently modified document
//                    return false;
//                }
//            }
//        }
//
//        private boolean isContentValid(String content) {
//            int fat = content.indexOf("=>");
//            if (fat>0) {
//                content = content.substring(fat+2);
//            }
//            int eq = content.indexOf("=");
//            if (eq>0) {
//                content = content.substring(eq+1);
//            }
//            if (content.startsWith(op)) {
//                content = content.substring(op.length());
//            }
//            String filter = content.trim().toLowerCase();
//            return ModelUtil.isNameMatching(content, dec) ||
//                    getProposedName(qualifier, dec, getUnit())
//                        .toLowerCase()
//                        .startsWith(filter);
//        }
//    }
//
//    @Deprecated
//    final class NestedLiteralCompletionProposal
//            implements ICompletionProposal, 
//                       ICompletionProposalExtension2,
//                       ICompletionProposalExtension6 {
//        
//        private final int loc;
//        private final int index;
//        private final String value;
//        
//        NestedLiteralCompletionProposal(String value, int loc, 
//                int index) {
//            this.value = value;
//            this.loc = loc;
//            this.index = index;
//        }
//        
//        public String getAdditionalProposalInfo() {
//            return null;
//        }
//        
//        @Override
//        public void apply(IDocument document) {
//            //the following awfulness is necessary because the
//            //insertion point may have changed (and even its
//            //text may have changed, since the proposal was
//            //instantiated).
//            try {
//                IRegion region =
//                        getCurrentArgumentRegion(document,
//                                loc, index,
//                                getFirstPosition());
//                String str = value;
//                int start = region.getOffset();
//                int len = region.getLength();
//                int end = start + len;
//                if (document.getChar(end)=='}') {
//                    str += " ";
//                }
//                document.replace(start, len, str);
//            } 
//            catch (BadLocationException e) {
//                e.printStackTrace();
//            }
//        }
//        
//        
//        @Override
//        public Point getSelection(IDocument document) {
//            return null;
//        }
//        
//        @Override
//        public String getDisplayString() {
//            return value;
//        }
//        
//
//        @Override
//        public StyledString getStyledDisplayString() {
//            StyledString result = new StyledString();
//            Highlights.styleFragment(result,
//                    getDisplayString(), false, null,
//                    getCompletionFont());
//            return result;
//        }
//
//        @Override
//        public Image getImage() {
//            return getDecoratedImage(CEYLON_LITERAL, 0, false);
//        }
//        
//        @Override
//        public IContextInformation getContextInformation() {
//            return null;
//        }
//        
//        @Override
//        public void apply(ITextViewer viewer, char trigger, 
//                int stateMask, int offset) {
//            apply(viewer.getDocument());
//        }
//        
//        @Override
//        public void selected(ITextViewer viewer, boolean smartToggle) {}
//        
//        @Override
//        public void unselected(ITextViewer viewer) {}
//        
//        @Override
//        public boolean validate(IDocument document,
//                int currentOffset, DocumentEvent event) {
//            if (event==null) {
//                return true;
//            }
//            else {
//                try {
//                    IRegion region =
//                            getCurrentArgumentRegion(document,
//                                    loc, index,
//                                    getFirstPosition());
//                    String content = 
//                            document.get(region.getOffset(),
//                                    currentOffset-region.getOffset());
//                    int eq = content.indexOf("=");
//                    if (eq>0) {
//                        content = content.substring(eq+1);
//                    }
//                    String filter = content.trim().toLowerCase();
//                    if (value.toLowerCase().startsWith(filter)) {
//                        return true;
//                    }
//                }
//                catch (BadLocationException e) {
//                    // ignore concurrently modified document
//                }
//                return false;
//            }
//        }
//    }
    
    private final CeylonParseController cpc;
    private final Declaration declaration;
    private final Reference producedReference;
    private final Scope scope;
    private final boolean includeDefaulted;
    private final boolean namedInvocation;
    private final boolean positionalInvocation;
    private final boolean qualified;
    private Declaration qualifyingValue;
    private boolean inheritance;

    @Deprecated
    InvocationCompletionProposal(
            int offset, String prefix,
            String desc, String text,
            Declaration dec,
            Reference producedReference,
            Scope scope,
            CeylonParseController controller,
            boolean includeDefaulted,
            boolean positionalInvocation,
            boolean namedInvocation,
            boolean inheritance,
            boolean qualified,
            Declaration qualifyingValue) {
        super(offset, prefix, new CompletionProposal.DeclarationImageRetriever(dec), 
                desc, text);
        this.cpc = controller;
        this.declaration = dec;
        this.producedReference = producedReference;
        this.scope = scope;
        this.includeDefaulted = includeDefaulted;
        this.namedInvocation = namedInvocation;
        this.positionalInvocation = positionalInvocation;
        this.inheritance = inheritance;
        this.qualified = qualified;
        this.qualifyingValue = qualifyingValue;
    }
//
//    @Deprecated
//    protected boolean isProposalMatching(String currentPrefix, String text){
//        if(super.isProposalMatching(currentPrefix, text))
//            return true;
//        for(String alias : declaration.getAliases()){
//            if(ModelUtil.isNameMatching(currentPrefix, alias))
//                return true;
//        }
//        return false;
//    }


    private Unit getUnit() {
        return cpc.getLastCompilationUnit().getUnit();
    }

//    @Deprecated
//    private DocumentChange createChange(IDocument document)
//            throws BadLocationException {
//        DocumentChange change = 
//                new DocumentChange("Complete Invocation", 
//                        document);
//        change.setEdit(new MultiTextEdit());
//        HashSet<Declaration> decs =
//                new HashSet<Declaration>();
//        Tree.CompilationUnit cu = cpc.getLastCompilationUnit();
//        if (qualifyingValue!=null) {
//            importProposals().importDeclaration(decs, qualifyingValue, cu);
//        }
//        if (!qualified) {
//            importProposals().importDeclaration(decs, declaration, cu);
//        }
//        if (positionalInvocation||namedInvocation) {
//            importProposals().importCallableParameterParamTypes(declaration,
//                    decs, cu);
//        }
//        int il= (int) importProposals().applyImports(change, decs, cu, document);
//        change.addEdit(createEdit(document));
//        offset+=il;
//        return change;
//    }

//    @Override
//    public void apply(IDocument document) {
//        try {
//            performChange(createChange(document));
//        }
//        catch (BadLocationException e) {
//            e.printStackTrace();
//        }
//        if (getPreferences()
//                .getBoolean(LINKED_MODE_ARGUMENTS)) {
//            activeLinkedMode(document);
//        }
//    }

//    @Deprecated
//    private void activeLinkedMode(IDocument document) {
//        if (declaration instanceof Generic) {
//            Generic generic = (Generic) declaration;
//            ParameterList paramList = null;
//            if (declaration instanceof Functional && 
//                    (positionalInvocation || namedInvocation)) {
//                Functional fd = (Functional) declaration;
//                List<ParameterList> pls =
//                        fd.getParameterLists();
//                if (!pls.isEmpty() && 
//                        !pls.get(0).getParameters()
//                            .isEmpty()) {
//                    paramList = pls.get(0);
//                }
//            }
//            if (paramList!=null) {
//                List<Parameter> params = 
//                        getParameters(paramList, 
//                                includeDefaulted, 
//                                namedInvocation);
//                if (!params.isEmpty()) {
//                    enterLinkedMode(document, params, null);
//                    return; //NOTE: early exit!
//                }
//            }
//            List<TypeParameter> typeParams = 
//                    generic.getTypeParameters();
//            if (!typeParams.isEmpty()) {
//                enterLinkedMode(document, null, typeParams);
//            }
//        }
//    }
    
//    @Override
//    public Point getSelection(IDocument document) {
//        int first = getFirstPosition();
//        if (first<=0) {
//            //no arg list
//            return super.getSelection(document);
//        }
//        int next = getNextPosition(document, first);
//        if (next<=0) {
//            //an empty arg list
//            return super.getSelection(document);
//        }
//        int middle = getCompletionPosition(first, next);
//        int start = offset-prefix.length()+first+middle;
//        int len = next-middle;
//        try {
//            if (document.get(start, len).trim()
//                    .equals("{}")) {
//                start++;
//                len=0;
//            }
//        } catch (BadLocationException e) {}
//        return new Point(start, len);
//    }
    
//    @Deprecated
//    protected int getCompletionPosition(int first, int next) {
//        return text.substring(first, first+next-1)
//                .lastIndexOf(' ') + 1;
//    }
//
//    @Deprecated
//    protected int getFirstPosition() {
//        int index;
//        if (namedInvocation) {
//            index = text.indexOf('{');
//        }
//        else if (positionalInvocation) {
//            index = text.indexOf('(');
//        }
//        else {
//            index = text.indexOf('<');
//        }
//        return index+1;
//    }
//    
//    @Deprecated
//    public int getNextPosition(IDocument document,
//            int lastOffset) {
//        int loc = offset-prefix.length();
//        int comma = -1;
//        try {
//            int start = loc+lastOffset;
//            int end = loc+text.length()-1;
//            if (text.endsWith(";")) {
//                end--;
//            }
//            comma =
//                    findCharCount(1, document,
//                            start, end,
//                            ",;", "", true)
//                        - start;
//        } 
//        catch (BadLocationException e) {
//            e.printStackTrace();
//        }
//        if (comma<0) {
//            int index;
//            if (namedInvocation) {
//                index = text.lastIndexOf('}');
//            }
//            else if (positionalInvocation) {
//                index = text.lastIndexOf(')');
//            }
//            else {
//                index = text.lastIndexOf('>');
//            }
//            return index - lastOffset;
//        }
//        return comma;
//    }
//
//    @Deprecated
//    public String getAdditionalProposalInfo() {
//        return getAdditionalProposalInfo(null);
//    }

    public String getAdditionalProposalInfo(IProgressMonitor monitor) {
        return getDocumentationFor(cpc, declaration,
                producedReference, monitor);
    }
    
//    @Deprecated
//    public void enterLinkedMode(IDocument document,
//            List<Parameter> params, 
//            List<TypeParameter> typeParams) {
//        boolean proposeTypeArguments = params==null;
//        int paramCount = 
//                proposeTypeArguments ? 
//                        typeParams.size() : 
//                        params.size();
//        if (paramCount==0) return;
//        try {
//            final int loc = offset-prefix.length();
//            int first = getFirstPosition();
//            if (first<=0) return; //no arg list
//            int next = getNextPosition(document, first);
//            if (next<=0) return; //empty arg list
//            LinkedModeModel linkedModeModel = 
//                    new LinkedModeModel();
//            int seq=0, param=0;
//            while (next>0 && param<paramCount) {
//                boolean voidParam = 
//                        !proposeTypeArguments &&
//                        params.get(param).isDeclaredVoid();
//                if (proposeTypeArguments ||
//                        positionalInvocation ||
//                        //don't create linked positions for
//                        //void callable parameters in named
//                        //argument lists
//                        !voidParam) {
//                    List<ICompletionProposal> props = 
//                            new ArrayList<ICompletionProposal>();
//                    if (proposeTypeArguments) {
//                        addTypeArgumentProposals(
//                                typeParams.get(seq), 
//                                loc, first, props, seq);
//                    }
//                    else if (!voidParam) {
//                        addValueArgumentProposals(
//                                params.get(param), 
//                                loc, first, props, seq, 
//                                param==params.size()-1);
//                    }
//                    int middle =
//                            getCompletionPosition(first, next);
//                    int start = loc+first+middle;
//                    int len = next-middle;
//                    if (voidParam) {
//                        start++;
//                        len=0;
//                    }
//                    ProposalPosition linkedPosition = 
//                            new ProposalPosition(
//                                    document, start, len, seq, 
//                                    props.toArray(NO_COMPLETIONS));
//                    addLinkedPosition(linkedModeModel, linkedPosition);
//                    first = first+next+1;
//                    next = getNextPosition(document, first);
//                    seq++;
//                }
//                param++; 
//            }
//            if (seq>0) {
//                CeylonEditor editor = 
//                        (CeylonEditor)
//                            getCurrentEditor();
//                installLinkedMode(editor, 
//                        document, linkedModeModel, this, 
//                        new LinkedMode.NullExitPolicy(),
//                        seq, loc+text.length());
//            }
//
//        }
//        catch (Exception e) {
//            e.printStackTrace();
//        }
//    }
//
//    @Deprecated
//    private void addValueArgumentProposals(
//            Parameter param, int loc, int first,
//            List<ICompletionProposal> props, 
//            int index, boolean last) {
//        if (param.getModel().isDynamicallyTyped()) {
//            return;
//        }
//        Type type = 
//                producedReference.getTypedParameter(param)
//                    .getType();
//        if (type==null) {
//            return;
//        }
//        Unit unit = getUnit();
//        String exactName = param.getName();
//        List<DeclarationWithProximity> proposals =
//                getSortedProposedValues(scope, unit,
//                        exactName);
//        //very special case for print()
//        String dname = declaration.getQualifiedNameString();
//        boolean print = "ceylon.language::print".equals(dname);
//        if (print) {
//            for (String value: getAssignableLiterals(
//                    unit.getStringType(), unit)) {
//                props.add(new NestedLiteralCompletionProposal(
//                            value, loc, index));
//            }
//        }
//        //stuff defined in the same block, along with
//        //stuff with fuzzily-matching name
//        for (DeclarationWithProximity dwp: proposals) {
//            if (dwp.getProximity()<=1) {
//                addValueArgumentProposal(param, loc, props,
//                        index, last, type, unit, dwp, null);
//            }
//        }
//        //this
//        ClassOrInterface ci =
//                getContainingClassOrInterface(scope);
//        if (ci!=null) {
//            if (ci.getType().isSubtypeOf(type)) {
//                props.add(new NestedLiteralCompletionProposal(
//                        "this", loc, index));
//            }
//        }
//        //literals
//        if (!print) {
//            for (String value: getAssignableLiterals(type, unit)) {
//                props.add(new NestedLiteralCompletionProposal(
//                            value, loc, index));
//            }
//        }
//        //stuff with lower proximity
//        for (DeclarationWithProximity dwp: proposals) {
//            if (dwp.getProximity()>1) {
//                addValueArgumentProposal(param, loc, props,
//                        index, last, type, unit, dwp, null);
//            }
//        }
//    }
//
//    @Deprecated
//    private void addValueArgumentProposal(
//            Parameter p, int loc,
//            List<ICompletionProposal> props, 
//            int index, boolean last,
//            Type type, Unit unit, 
//            DeclarationWithProximity dwp,
//            DeclarationWithProximity qualifier) {
//        if (qualifier==null && dwp.isUnimported()) {
//            return;
//        }
//        Declaration d = dwp.getDeclaration();
//        if (d instanceof NothingType) {
//            return;
//        }
//        String pname =
//                d.getUnit().getPackage()
//                    .getNameAsString();
//        boolean isInLanguageModule =
//                qualifier==null &&
//                pname.equals(Module.LANGUAGE_MODULE_NAME);
//        Declaration qdec =
//                qualifier==null ? null :
//                    qualifier.getDeclaration();
//        if (d instanceof Value) {
//            Value value = (Value) d;
//            if (isInLanguageModule &&
//                    isIgnoredLanguageModuleValue(value)) {
//                return;
//            }
//            Type vt = value.getType();
//            if (vt!=null && !vt.isNothing()) {
//                if (withinBounds(type, vt, scope)) {
//                    boolean isIterArg = 
//                            namedInvocation && last && 
//                            unit.isIterableParameterType(type);
//                    boolean isVarArg = 
//                            p.isSequenced() && 
//                            positionalInvocation;
//                    String op =
//                            isIterArg || isVarArg ?
//                                    "*" : "";
//                    props.add(new NestedCompletionProposal(
//                            d, qdec, loc, index, false, op));
//                }
//                if (qualifier==null && 
//                        getPreferences()
//                            .getBoolean(CHAIN_LINKED_MODE_ARGUMENTS)) {
//                    Collection<DeclarationWithProximity> members = 
//                            value.getTypeDeclaration()
//                                .getMatchingMemberDeclarations(
//                                        unit, scope, "", 0)
//                                .values();
//                    for (DeclarationWithProximity mwp: members) {
//                        addValueArgumentProposal(p, loc, props, 
//                                index, last, type, unit, mwp, dwp);
//                    }
//                }
//            }
//        }
//        if (d instanceof Function) {
//            if (!d.isAnnotation()) {
//                Function method = (Function) d;
//                if (isInLanguageModule &&
//                        isIgnoredLanguageModuleMethod(method)) {
//                    return;
//                }
//                Type mt = method.getType();
//                if (mt!=null && !mt.isNothing() && 
//                        withinBounds(type, mt, scope)) {
//                    boolean isIterArg = 
//                            namedInvocation && last && 
//                            unit.isIterableParameterType(type);
//                    boolean isVarArg = 
//                            p.isSequenced() && 
//                            positionalInvocation;
//                    String op =
//                            isIterArg || isVarArg ?
//                                    "*" : "";
//                    props.add(new NestedCompletionProposal(
//                            d, qdec, loc, index, false, op));
//                }
//            }
//        }
//        if (d instanceof Class) {
//            Class clazz = (Class) d;
//            if (!clazz.isAbstract() && !d.isAnnotation()) {
//                if (isInLanguageModule &&
//                        isIgnoredLanguageModuleClass(clazz)) {
//                    return;
//                }
//                Type ct = clazz.getType();
//                if (ct!=null &&
//                        (withinBounds(type, ct, scope) || 
//                         clazz.equals(type.getDeclaration()))) {
//                    boolean isIterArg = 
//                            namedInvocation && last && 
//                            unit.isIterableParameterType(type);
//                    boolean isVarArg = 
//                            p.isSequenced() && 
//                            positionalInvocation;
//                    String op =
//                            isIterArg || isVarArg ?
//                                    "*" : "";
//                    if (clazz.getParameterList()!=null) {
//                        props.add(new NestedCompletionProposal(
//                                d, qdec, loc, index, false, op));
//                    }
//                    for (Declaration m: clazz.getMembers()) {
//                        if (m instanceof FunctionOrValue &&
//                                m.isConstructor() &&
//                                m.isShared() &&
//                                m.getName()!=null) {
//                            props.add(new NestedCompletionProposal(
//                                    m, d, loc, index, false, op));
//                        }
//                    }
//                }
//            }
//        }
//    }
//
//    @Deprecated
//    private void addTypeArgumentProposals(
//            TypeParameter tp,
//            final int loc, int first,
//            List<ICompletionProposal> props,
//            final int index) {
//        Unit unit = getUnit();
//        Class ed = unit.getExceptionDeclaration();
//        for (DeclarationWithProximity dwp:
//                getSortedProposedValues(scope, unit, null)) {
//            Declaration dec = dwp.getDeclaration();
//            if (dec instanceof TypeDeclaration &&
//                    !dwp.isUnimported()) {
//                TypeDeclaration td = (TypeDeclaration) dec;
//                Type t = td.getType();
//                if (!t.isNothing() &&
//                        td.getTypeParameters().isEmpty() && 
//                        !td.isAnnotation() &&
//                        !td.inherits(ed)) {
//                    String pname =
//                            td.getUnit()
//                                .getPackage()
//                                .getNameAsString();
//                    if (pname.equals(Module.LANGUAGE_MODULE_NAME)) {
//                        if (isIgnoredLanguageModuleType(td)) {
//                            continue;
//                        }
//                    }
//                    if (inheritance && tp.isSelfType() ?
//                            scope.equals(td) :
//                            isInBounds(tp.getSatisfiedTypes(), t)) {
//                        props.add(new NestedCompletionProposal(
//                                dec, null, loc, index, true, ""));
//                    }
//                }
//            }
//        }
//    }

    @Override
    public IContextInformation getContextInformation() {
        if (namedInvocation || positionalInvocation) { //TODO: context info for type arg lists!
            if (declaration instanceof Functional) {
                Functional fd = (Functional) declaration;
                List<ParameterList> pls = 
                        fd.getParameterLists();
                if (!pls.isEmpty()) {
                    int argListOffset = 
                            isParameterInfo() ?
                                this.offset :
                                offset-prefix.length() + 
                                text.indexOf(namedInvocation?'{':'(');
                    return new ParameterContextInformation(
                            declaration, producedReference, 
                            getUnit(), pls.get(0), 
                            argListOffset, 
                            includeDefaulted, 
                            namedInvocation);
                }
            }
        }
        return null;
    }
    
    boolean isParameterInfo() {
        return false;
    }
    
    static void addFakeShowParametersCompletion(final Node node, 
            final CeylonParseController cpc, 
            final List<ICompletionProposal> result) {
        Tree.CompilationUnit upToDateAndTypeChecked =
                cpc.getTypecheckedRootNode();
        if (upToDateAndTypeChecked == null) {
            return;
        }
        new Visitor() {
            @Override
            public void visit(Tree.InvocationExpression that) {
                Tree.ArgumentList al = 
                        that.getPositionalArgumentList();
                if (al==null) {
                    al = that.getNamedArgumentList();
                }
                if (al!=null) {
                    Integer startIndex = al.getStartIndex();
                    Integer startIndex2 = node.getStartIndex();
                    if (startIndex!=null && startIndex2!=null &&
                            startIndex.intValue()==startIndex2.intValue()) {
                        Tree.Primary primary = that.getPrimary();
                        if (primary instanceof Tree.MemberOrTypeExpression) {
                            Tree.MemberOrTypeExpression mte = 
                                    (Tree.MemberOrTypeExpression) 
                                        primary;
                            if (mte.getDeclaration()!=null && 
                                    mte.getTarget()!=null) {
                                result.add(new ParameterInfo(
                                        al.getStartIndex(),
                                        mte.getDeclaration(), 
                                        mte.getTarget(), 
                                        node.getScope(), cpc,
                                        al instanceof Tree.NamedArgumentList));
                            }
                        }
                    }
                }
                super.visit(that);
            }
        }.visit(upToDateAndTypeChecked);
    }
    
}
